package it.polito.connectedcar.tcc;

import it.polito.appeal.traci.SumoTraciConnection;
import it.polito.connectedcar.tcc.network.TCCNetworkConnectionManager;
import it.polito.connectedcar.tcc.network.TCCTrafficLightsMessageQueueMainLoop;
import it.polito.connectedcar.tcc.network.TCCVehiclesMessageQueueMainLoop;
import it.polito.connectedcar.tcc.tl.TCCTrafficLightsManager;
import it.polito.connectedcar.tcc.zone.TCCZonesManager;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * This is the TCC main class. It starts threads managing the network sockets
 * for traffic lights messages and vehicles messages. When started , it
 * retrieves the information about the Zones/Tokens it has to manage and waits
 * for messages coming from the network.
 * 
 * @author Nicola Aresta
 * 
 */
public class TCCMain {

	private static final int vehiclesMaxThreads = 6;
	private static final int trafficLightsMaxThreads = 3;
	/**
	 * standalone run of a TCC
	 * 
	 * @param args
	 */

	private TCCNetworkConnectionManager tnm;
	private TCCTrafficLightsManager trafficLightsManager;
	private TCCZonesManager zonesManager;
	private List<TCCVehiclesMessageQueueMainLoop> tccVehiclesQueueReaders;
	private List<TCCTrafficLightsMessageQueueMainLoop> tccTrafficLightsQueueReaders;

	public static void main(String[] args) {

		/* receive the token indexes it has to manage */
		Set<Integer> tokensIndexes = new HashSet<Integer>();
		for (String tokenInd : args) {
			try {
				tokensIndexes.add(Integer.parseInt(tokenInd));
			} catch (NumberFormatException nfe) {
				nfe.printStackTrace();
				System.err.println("invalid TCC token's index to start");
			}
		}
		SumoTraciConnection conn;
		try {
			conn = new SumoTraciConnection(InetAddress.getByName("192.168.1.4"), 9001);
			new TCCMain(tokensIndexes, conn);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

	public TCCMain(Set<Integer> tokensIndexes,
			SumoTraciConnection SUMOConnection) {
		try {
			/*
			 * given these indexes , read from central database: the Tokens,zone
			 * coordinates, quadrants informations and the adjacent tokens
			 */

			zonesManager = TCCZonesManager.getInstance();
			/* read all traffic lights info */
			trafficLightsManager = TCCTrafficLightsManager.getInstance();
			if (!trafficLightsManager.isSetup()) {
				trafficLightsManager.setup(SUMOConnection);
			}
		} catch (Exception e1) {
			e1.printStackTrace();
			System.err
					.println("unable to load information about traffic lights");
			System.exit(1);
		}

		/*
		 * start the following threads : - the Main Thread in charge of
		 * processing messages coming from the vehicles - the Network thread in
		 * charge of sending and receiving datagram packets
		 */

		try {

			TCCQueuesWrapper taw = new TCCQueuesWrapper();
			tccVehiclesQueueReaders = new ArrayList<TCCVehiclesMessageQueueMainLoop>();
			for (int i = 0; i < vehiclesMaxThreads; i++) {
				TCCVehiclesMessageQueueMainLoop tccVehiclesMessageQueueMainLoop = new TCCVehiclesMessageQueueMainLoop(
						zonesManager, trafficLightsManager,
						taw.getReadMessagesQueue(),
						taw.getToWriteMessagesQueue());
				tccVehiclesQueueReaders.add(tccVehiclesMessageQueueMainLoop);
				tccVehiclesMessageQueueMainLoop.start();
			}
			tccTrafficLightsQueueReaders = new ArrayList<TCCTrafficLightsMessageQueueMainLoop>();
			for (int i = 0; i < trafficLightsMaxThreads; i++) {
				TCCTrafficLightsMessageQueueMainLoop tccTrafficLightsMessageQueueMainLoop = new TCCTrafficLightsMessageQueueMainLoop(
						trafficLightsManager,
						taw.getTrafficLightReadMessageQueue());
				tccTrafficLightsQueueReaders.add(tccTrafficLightsMessageQueueMainLoop);
				tccTrafficLightsMessageQueueMainLoop.start();
			}

			tnm = new TCCNetworkConnectionManager(taw.getReadMessagesQueue(),
					taw.getTrafficLightReadMessageQueue(),
					taw.getToWriteMessagesQueue());

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void onReceive(DatagramPacket dp) {
		/*
		 * 1)check SourceAddress if it already exists in the system , the
		 * message must be a position update, otherwise it should be an
		 * authentication request
		 * 
		 * 2) check the data
		 */
	}
}
